home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
utils
/
which5.zoo
/
which5.c
< prev
Wrap
C/C++ Source or Header
|
1992-07-03
|
7KB
|
308 lines
/*
* which [-i] [-a] [--] [<command>]
* alias which alias !\$ \| /usr/local/bin/which -i !\*
* alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
* which()
* {
* eval last=\"\$$#\"
* set | sed -n "/^$last(){$/,/^}$/p" |
* /usr/local/bin/which -i ${1+"$@"}
* }
*
* Author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
* First change:
* Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
* the access() system call considering everything executable for
* root (!), so we give root a special treatment. :-(
* `which', `which -i' and `which -a' with no further arguments now
* return the PATH environment variable, split up into its components.
* The aliases defined above are slightly different from the previous
* version - now it's the shell who's doing the alias checking.
* Second change:
* Added support for shell functions and multiline aliases, added the
* `--' option, changed the source style.
* Third change:
* To hell with access()!
* Now stat() is used to give the right answer even if the effective
* uid (gid) differs from the real uid (gid).
* We can't use setuid(geteuid()), because that's nonportable. :-(
* Fourth change:
* Jim Meyering <meyering@cs.utexas.edu> notes convert() will clobber
* the stack if the PATH is longer than BUF_SIZE - 1 characters.
* I've changed convert() altogether to return a path vector (cf. argv),
* whose components are the respective directories in the PATH.
* Furthermore in printing the PATH there are no trailing colons anymore.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef __GNUC__
/* for all the extern progs... */
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#endif
#if defined(__GNUC__) && defined(atarist)
/* note: tcsh keeps PATH like .:/dev/c/bin:... but when it sets up an env
for a prog, it converts it to .,c:\bin,... */
#define DIRSEP ','
#define SLASH '\\'
#else
#define DIRSEP ':'
#define SLASH '/'
#endif
#define BUF_SIZE 512
#define M_USR 0700
#define M_GRP 0070
#define M_OTH 0007
#define X_ALL 0111
#define R_ALL 0444
char Version[] =
"@(#)which 5.0 90/03/24 Maarten Litmaath @ VU Informatika Amsterdam";
char *Prog;
#ifdef atarist
/* we need to look for files with extensions, too... */
char *extn[] = {"", ".ttp", ".prg", ".tos", ".acc",
".csh", ".sh", ".g", (char *)0};
#endif
void usage()
{
fprintf(stderr, "%s\n\n", Version);
fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
exit(1);
}
#ifdef __GNUC__
char **convert();
#endif
void main(argc, argv)
int argc;
register char **argv;
{
register char *path, *s, **pathv, **p;
#ifdef __GNUC__
char buf[BUF_SIZE];
#else
char *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE], **convert();
#endif
int all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
xmask, rmask;
struct stat st;
void usage();
#ifdef atarist
/* to deal with extensions... */
int stret;
char *pend;
char **pextn;
#endif
Prog = *argv++;
--argc;
while (!stop && (s = *argv) && (*s == '-')) {
++argv;
--argc;
++s;
while (*s)
switch (*s++) {
case 'a':
all = 1;
break;
case 'i':
inter = 1;
break;
case '-':
stop = 1;
break;
default:
usage();
}
}
if (argc > 1)
usage();
if (inter && *argv) {
while (fgets(buf, sizeof buf, stdin)) {
if (!found) {
/*!!! printf("%s", *argv);*/
printf("%s:", *argv);
found = 1;
}
/*!!! printf("\t%s", buf);*/
printf("\taliased to %s", buf);
}
if (found && !all)
exit(0);
}
if (!(path = getenv("PATH"))) {
fprintf(stderr, "%s: no PATH in environment!\n", Prog);
exit(1);
}
if (!*path)
path = "."; /* another dubious convention */
pathv = convert(path); /* convert path string to vector */
if (!*argv) { /* print path if no more arguments */
while (*pathv)
puts(*pathv++);
exit(0);
}
uid = geteuid();
gid = getegid();
if (uid == 0) {
xmask = X_ALL;
rmask = R_ALL;
}
for (p = pathv; path = *p++; ) { /* try every component */
s = buf;
while (*s++ = *path++)
;
(void) strcpy(s, *argv);
*--s = SLASH;
#ifdef atarist
/*
* here we deal with extensions. keep a ptr to null at
* end of basic string. this assumes user did NOT give
* a suffix! then we move along the list until we find
* a regular file. if we get thru the loop, and if list
* was exhausted, next. otherwise test again if reg file.
*/
pend = &buf[strlen(buf)]; /* -> null at end */
for (pextn = extn; *pextn; pextn++)
{
strcpy (pend, *pextn);
/*fprintf(stderr,"test %s\n",buf);*/
if (stret = stat(buf, &st) == 0
&& (st.st_mode & S_IFMT) == S_IFREG)
break;
}
if (*pextn == NULL)
continue;
if (stret == 0 && (st.st_mode & S_IFMT) != S_IFREG)
continue;
#else
if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
continue;
#endif
/* file exists and is regular */
if (uid != 0) {
mask = st.st_uid == uid ? M_USR :
st.st_gid == gid ? M_GRP : M_OTH;
xmask = X_ALL & mask;
rmask = R_ALL & mask;
}
if (!(st.st_mode & xmask))
continue;
/* file is executable */
*s = 0;
if (stat(buf, &st) != 0) {
perror(buf);
continue;
}
if (!(st.st_mode & rmask)) {
fprintf(stderr,
"%s: %s found in unreadable directory %s!\n",
Prog, *argv, buf);
found = 1;
continue;
}
/* directory is readable */
*s = SLASH;
puts(buf);
if (!all)
exit(0);
found = 1;
}
if (found)
exit(0);
fprintf(stderr, "%s not found in:\n", *argv);
while (*pathv)
fprintf(stderr, "%s\n", *pathv++);
exit(1);
}
char **convert(path)
char *path;
{
register char *s, c;
register int pathc; /* the length of the path vector */
#ifdef __GNUC__
char **v, **pathv;
#else
char **v, **pathv, *malloc();
#endif
for (s = path, pathc = 2; c = *s++; )
if (c == DIRSEP)
++pathc;
if (!(pathv = (char **) malloc(pathc * sizeof(char *)))) {
perror("malloc");
exit(1);
}
for (s = path, v = pathv; (c = *s) != '\0'; ) {
if (c == DIRSEP) {
/*
* This colon is spurious. According to some
* dubious convention it is made equivalent to a dot.
*/
*v++ = ".";
if (*++s == '\0')
*v++ = ".";
/*
* The PATH ended in a spurious colon.
* To be consistent we add another dot
* to the path vector. One day you'll
* be glad we did.
*/
} else {
*v++ = s;
while ((c = *++s) != '\0')
if (c == DIRSEP) {
*s++ = '\0';
if (*s == '\0')
*v++ = ".";
/*
* The PATH ended in a
* (spurious) colon, so
* add dot to the vector.
*/
break;
}
}
}
*v = 0; /* Signal the end of the path vector. */
return pathv;
}